package com.example.yuanboot.service.common.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.example.yuanboot.common.exception.BizException;
import com.example.yuanboot.mapper.system.QuartzMapper;
import com.example.yuanboot.model.dto.system.JobAndTrigger;
import com.example.yuanboot.model.dto.system.JobForm;
import com.example.yuanboot.model.vo.page.PageInput;
import com.example.yuanboot.service.common.IQuartzBizService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;

/**
 * <p>
 * Job Service
 * </p>
 *
 * @author abs
 * @date 2021/3/31 14:22
 */
@RequiredArgsConstructor
//@Service
@Slf4j
public class QuartzBizServiceImpl implements IQuartzBizService {

    private final Scheduler scheduler;
    private final QuartzMapper quartzMapper;

    /**
     * 添加并启动定时任务
     *
     * @param form 表单参数 {@link JobForm}
     * @return {@link JobDetail}
     * @throws Exception 异常
     */
    @Override
    public void addJob(JobForm form) throws SchedulerException {
        // 启动调度器 TODO
        // scheduler.start();

        // 构建Job信息
        JobDetail jobDetail = JobBuilder.newJob(ClassUtil.loadClass(form.getJobClassName())).withIdentity(form.getJobName(), form.getJobGroupName())
                .withDescription(form.getDescription()).build();

        // Cron表达式调度构建器(即任务执行的时间)
        CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(form.getCronExpression());

        //根据Cron表达式构建一个Trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger_" + form.getJobName(), form.getJobGroupName())
                .startNow().withSchedule(cron).build();

        // 自定义方法执行
        //trigger.getJobDataMap().put("jobMethodName", form.getJobMethodName());

        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 删除定时任务
     *
     * @param form 表单参数 {@link JobForm}
     * @throws SchedulerException 异常
     */
    @Override
    public void deleteJob(JobForm form) throws SchedulerException {
        if (StrUtil.hasBlank(form.getJobGroupName(), form.getJobName())) {
            throw new BizException("参数不能为空");
        }
        // 获取出发KEY
        TriggerKey triggerKey = TriggerKey.triggerKey("trigger_" + form.getJobName(), form.getJobGroupName());
        // 停止触发器
        scheduler.pauseTrigger(triggerKey);
        // 移除触发器
        scheduler.unscheduleJob(triggerKey);
        // 删除任务
        scheduler.deleteJob(JobKey.jobKey(form.getJobName(), form.getJobGroupName()));
    }

    /**
     * 暂停定时任务
     *
     * @param form 表单参数 {@link JobForm}
     * @throws SchedulerException 异常
     */
    @Override
    public void pauseJob(JobForm form) throws SchedulerException {
        if (StrUtil.hasBlank(form.getJobGroupName(), form.getJobName())) {
            throw new BizException("参数不能为空");
        }
        scheduler.pauseJob(JobKey.jobKey(form.getJobName(), form.getJobGroupName()));
    }

    /**
     * 暂停所有任务
     * @author abs
     * @date 2021/4/9 17:46
     */
    @Override
    public void pauseAllJob() throws SchedulerException {
        scheduler.pauseAll();
    }

    /**
     * 恢复定时任务
     *
     * @param form 表单参数 {@link JobForm}
     * @throws SchedulerException 异常
     */
    @Override
    public void resumeJob(JobForm form) throws SchedulerException {
        if (StrUtil.hasBlank(form.getJobGroupName(), form.getJobName())) {
            throw new BizException("参数不能为空");
        }
        scheduler.resumeJob(JobKey.jobKey(form.getJobName(), form.getJobGroupName()));
    }

    /**
     * 恢复所有任务
     *
     * @author abs
     * @date 2021/4/9 17:57
     */
    @Override
    public void resumeAllJob() throws SchedulerException {
        scheduler.resumeAll();
    }

    /**
     * 重新配置定时任务
     *
     * @param form 表单参数 {@link JobForm}
     * @throws Exception 异常
     */
    @Override
    public void updateJob(JobForm form) throws SchedulerException {

        // 获取出发KEY
        TriggerKey triggerKey = TriggerKey.triggerKey("trigger_" + form.getJobName(), form.getJobGroupName());

        // 表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(form.getCronExpression());
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

        // 根据Cron表达式构建一个Trigger
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

        // 自定义方法执行
        //trigger.getJobDataMap().put("jobMethodName", form.getJobMethodName());

        // 按新的trigger重新设置job执行
        scheduler.rescheduleJob(triggerKey, trigger);

    }

    /**
     * 查询定时任务列表
     *
     * @param pageInput 分页参数
     * @return 定时任务列表
     */
    @Override
    public IPage<JobAndTrigger> list(JobForm form, PageInput pageInput) {
        IPage<JobAndTrigger> page = quartzMapper.list(new Page<>(pageInput.getPage(), pageInput.getSize()), form);
        page.getRecords().forEach(e -> {
            try {
                if(ArrayUtil.isNotEmpty(e.getJobData())){
                    ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(e.getJobData()));
                    JobDataMap jobDataMap = (JobDataMap) objectInputStream.readObject();
                    e.setJobMethodName((String) jobDataMap.get("jobMethodName"));
                    e.setJobData(null);
                }
            } catch (Exception ex) {
                log.error("job method error", ex);
            }
        });
        return page;
    }

    /**
     * 执行一次
     *
     * @param form :
     * @return
     * @author abs
     * @date 2021/3/25 11:25
     */
    @Override
    public void triggerJob(JobForm form) throws SchedulerException {
        if (StrUtil.hasBlank(form.getJobGroupName(), form.getJobName())) {
            throw new BizException("参数不能为空");
        }
        JobKey jobKey = JobKey.jobKey(form.getJobName(), form.getJobGroupName());
        scheduler.triggerJob(jobKey);
    }
}
